/**
 * \file
 *
 * This file contains the definitions for the paticle class, which can
 * be used in place of rigid bodies for simpler simulations or
 * assemblies.
 */


#ifndef PARTICLE_H
#define PARTICLE_H



#include "Maths/precision.h"
#include "Maths/Vector3D.h"


namespace SimPhy
{

class Particle
{
public:

    /**
     * \name Constructor and Destructor
     *
     * Create a particule at the position 0 m with 0 m/s velocity, 0 m/s^2 acceleration and 0 forces.
     * It has a mass of 1kg and a damping factor of 1.
     *
     */
    Particle();

    /**
     * \name Accessor Functions for the Particle's State
     *
     * These functions provide access to the particle's
     * characteristics or state.
     */

    /** \return the mass of the particle */
    real getMass() const;

    /**
     * Sets the mass of the particle.
     *
     * \param mass The new mass of the body. This may not be zero.
     * Small masses can produce unstable rigid bodies under
     * simulation.
     */
    void setMass(const real mass);

    /**
     * Gets the inverse mass of the particle.
     *
     * \return The current inverse mass of the particle.
     */
    real getInverseMass() const;


    /**
     * Sets the inverse mass of the particle.
     *
     * \param inverseMass The new inverse mass of the body. This
     * may be zero, for a body with infinite mass
     * (i.e. unmovable).
     */
    void setInverseMass(const real inverseMass);


    /**
     * Returns true if the mass of the particle is not-infinite.
     */
    bool hasFiniteMass() const;

    /**
     * Sets the damping of the particle.
     */
    void setDamping(const real damping);

    /**
     * Gets the current damping value.
     */
    real getDamping() const;

    /**
     * Gets the position of the particle.
     *
     * \return The position of the particle.
     */
    Vector3D getPosition() const;

    /**
     * Sets the position of the particle.
     *
     * \param position The new position of the particle.
     */
    void setPosition(const Vector3D &position);

    /**
     * Gets the velocity of the particle.
     *
     * @return The velocity of the particle. The velocity is
     * given in world local space.
     */
    Vector3D getVelocity() const;

    /**
     * Sets the velocity of the particle.
     *
     * \param velocity The new velocity of the particle.
     */
    void setVelocity(const Vector3D &velocity);

    /**
     * Gets the acceleration of the particle.
     *
     * \return The acceleration of the particle. The acceleration is
     * given in world local space.
     */
    Vector3D getAcceleration() const;

    /**
     * Sets the constant acceleration of the particle.
     *
     * \param acceleration The new acceleration of the particle.
     */
    void setAcceleration(const Vector3D &acceleration);

    /**
     * Gets the force(s) applied to the particle.
     *
     * \return The force(s) applied to the particle.
     */
    Vector3D getForces() const;

    /**
     * Adds the given force to the particle, to be applied at the
     * next iteration only.
     *
     * \param force The force to apply.
     */
    void addForce(const Vector3D &force);

    /**
     * Clears the forces applied to the particle. This will be
     * called automatically after each integration step.
     */
    void clearForces();


   /**
    * Integrates the particle forward in time by the given amount.
    * This function uses a Newton-Euler integration method, which is a
    * linear approximation to the correct integral. For this reason it
    * may be inaccurate in some cases.
    */
    void explicitEulerIntegrate(real timeStep);

    /** \return the kinetic energy of the particle. */
    real kineticEnergy() const;

protected:

    /**
     * Holds the vector position of the particle in
     * world space.
     */
    Vector3D m_position;

    /**
     * Holds the vector velocity of the particle in
     * world space.
     */
    Vector3D m_velocity;

    /**
     * Holds the vector acceleration of the particle.  This value
     * can be used to set acceleration due to gravity (its primary
     * use), or any other constant acceleration.
     */
    Vector3D m_acceleration;

    /**
     * Holds the accumulated force to be applied at the next
     * simulation iteration only. This value is zeroed at each
     * integration step.
     */
    Vector3D m_appliedForces;

    /**
     * Holds the amount of damping applied to linear
     * motion. Damping is required to remove energy added
     * through numerical instability in the integrator.
     */
    real m_damping;

    /**
     * Holds the inverse of the mass of the particle. It
     * is more useful to hold the inverse mass because
     * integration is simpler, and because in real time
     * simulation it is more useful to have objects with
     * infinite mass (immovable) than zero mass
     * (completely unstable in numerical simulation).
     * It must be positive.
     */
     real m_inverseMass;


};

/** Writes the given particle to the given stream and returns a reference to the stream. */
std::ostream& operator<<( std::ostream &stream, Particle const& particle );



}

#endif // PARTICLE_H
